﻿// --------------------------------------------------------------------------------------------------------------------
// <copyright file="AssignSpecialToClosestRegular.cs" company="Luis de la Torre">
//   Copyright Luis de la Torre, unless otherwise indicated
// </copyright>
// <summary>
//   The assign special to closest regular.
// </summary>
// --------------------------------------------------------------------------------------------------------------------

namespace PVRP_SR
{
    using System.Collections.Generic;
    using System.Diagnostics;

    /// <summary>
    /// The assign special to closest regular.
    /// </summary>
    internal class AssignSpecialToClosestRegular : ImprovementHeuristic
    {
        #region Fields

        /// <summary>
        /// The _closest regular.
        /// </summary>
        private Dictionary<int, int[]> closestRegular;

        #endregion

        #region Constructors and Destructors

        /// <summary>
        /// Initializes a new instance of the <see cref="AssignSpecialToClosestRegular"/> class.
        /// </summary>
        /// <param name="solution">
        /// The solution.
        /// </param>
        public AssignSpecialToClosestRegular(PvrpSrSolution solution)
        {
            this.closestRegular = new Dictionary<int, int[]>(solution.Instance.NumNodesTotal);
            for (int i = solution.Instance.NumNodesRegular;
                 i < solution.Instance.NumNodesRegular + solution.Instance.NumNodesSpecial;
                 i++)
            {
                this.closestRegular.Add(i, new int[solution.Instance.NumDays]);
            }
        }

        #endregion

        #region Public Methods and Operators

        /// <summary>
        /// The improve solution.
        /// </summary>
        /// <param name="solution">
        /// The solution.
        /// </param>
        public override void ImproveSolution(PvrpSrSolution solution)
        {
            this.CalcDistances(solution);
            this.AssignToClosest(solution);
        }

        #endregion

        #region Methods

        /// <summary>
        /// The assign to closest.
        /// </summary>
        /// <param name="solution">
        /// The solution.
        /// </param>
        private void AssignToClosest(PvrpSrSolution solution)
        {
            for (int s = solution.Instance.NumNodesRegular;
                 s < solution.Instance.NumNodesRegular + solution.Instance.NumNodesSpecial;
                 s++)
            {
                Debug.Assert(solution.StoRAssignments.ContainsKey(s), "solution should contain special customer s");
                for (int t = 0; t < solution.Instance.NumDays; t++)
                {
                    solution.StoRAssignments[s][t] = this.closestRegular[s][t];
                }
            }
        }

        /// <summary>
        /// for each special node find the closest regular node
        /// </summary>
        /// <param name="solution">
        /// The solution
        /// </param>
        private void CalcDistances(PvrpSrSolution solution)
        {
            for (int s = solution.Instance.NumNodesRegular;
                 s < solution.Instance.NumNodesRegular + solution.Instance.NumNodesSpecial;
                 s++)
            {
                for (int t = 0; t < solution.Instance.NumDays; t++)
                {
                    int closestReg = 0;
                    double closestRegDistance = double.MaxValue;
                    for (int i = 1; i < solution.Instance.NumNodesRegular; i++)
                    {
                        if (!(solution.Instance.Demands[t][i] >= 0))
                        {
                            continue;
                        }

                        if (!(solution.Instance.Distances[s][i] < closestRegDistance))
                        {
                            continue;
                        }

                        closestReg = i;
                        closestRegDistance = solution.Instance.Distances[s][i];
                    }

                    this.closestRegular[s][t] = closestReg;
                }
            }
        }

        #endregion
    }
}